#include <util/delay.h>
#include <avr/io.h>
#include <util/twi.h>

static s_AddresBits = 16;
static s_eeprom_addr = 16;

/*
unsigned char I2C_Begin( unsigned char addr )
{
	char retries = 10;
	char err = 0;

	goto start;

retry:
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
	retries--;
	//PrintHex8( retries );
	_delay_us(500);
	if ( retries == 0 )
		return err;
    err = 0;
start:

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if ( TW_STATUS != TW_START )
	{
		err = 0xe1;
		goto retry;
	}

	// set I2C Address
	TWDR = addr;
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if (TW_STATUS != TW_MT_SLA_ACK)
	{
		err = 0xe2;
		goto retry;
	}

	return 0;
}

unsigned char I2C_Send(unsigned char data)
{
	TWDR = data;
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if (TW_STATUS != TW_MT_DATA_ACK )
	{
		err = 0xe3;
		goto retry;
	}
}

unsigned char I2C_Receive(unsigned char addr, unsigned char length, unsigned char *data)
{
	unsigned char old_length = length;

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if ( TW_STATUS != TW_REP_START )
		return 0xf1;

	TWDR = addr | 1;
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if (TW_STATUS != TW_MR_SLA_ACK) 
		return 0xf2;

	while( length )
	{
		if (length == 1) 
		{
			TWCR = (1 << TWINT) | (1 << TWEN);
		}
		else
		{
			TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
		}

		while (!(TWCR & (1 << TWINT)));
		if ( (TW_STATUS == TW_MR_DATA_ACK) || (TW_STATUS == TW_MR_DATA_NACK) )
		{
			*out = TWDR;
			out++;
			length--;
		}
	}

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

	return old_length - length;
}
*/

void Set16BitsAddress()
{
	s_AddresBits = 16;
}

void Set8BitsAddress()
{
	s_AddresBits = 8;
}


char SetEpromAddress( unsigned char eprom_addr, unsigned int addr)
{
	s_eeprom_addr = eprom_addr;
	char retries = 10;
	char err = 0;

	goto start;

retry:
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
	retries--;
	//PrintHex8( retries );
	_delay_us(500);
	if ( retries == 0 )
		return err;

start:

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if ( TW_STATUS != TW_START )
	{
		err = 0xe1;
		goto retry;
	}

	// set I2C Address
	TWDR = eprom_addr;
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if (TW_STATUS != TW_MT_SLA_ACK)
	{
		err = 0xe2;
		goto retry;
	}


	if ( s_AddresBits == 16 )
	{
		TWDR = addr>>8;
		TWCR = (1 << TWINT) | (1 << TWEN);
		while ( !( TWCR & ( 1 << TWINT ) ) );
		if (TW_STATUS != TW_MT_DATA_ACK )
		{
			err = 0xe3;
			goto retry;
		}
	}

	_delay_us(100);

	TWDR = (unsigned char)( addr & 0xff );
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if ( TW_STATUS != TW_MT_DATA_ACK )
	{
		err = 0xe4;
		goto retry;
	}

	//TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

	_delay_us(100);


	return 1;
}

char SetEpromAddress8( unsigned char eprom_addr, unsigned char addr)
{
	TWSR = 0;
	TWBR = 6;
	Set8BitsAddress();
	return SetEpromAddress( eprom_addr, addr);
}

char SetEpromAddress16( unsigned char eprom_addr, unsigned int addr)
{
	TWSR = 0;
	TWBR = 6;
	Set16BitsAddress();
	return SetEpromAddress( eprom_addr, addr);
}

unsigned char ReadFromEprom( unsigned char length, unsigned char *out)
{
	unsigned char old_length = length;

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if ( TW_STATUS != TW_REP_START )
		return 0xf1;

	TWDR = s_eeprom_addr | 1;
	TWCR = (1 << TWINT) | (1 << TWEN);
	while ( !( TWCR & ( 1 << TWINT ) ) );
	if (TW_STATUS != TW_MR_SLA_ACK) 
		return 0xf2;

	while( length )
	{
		if (length == 1) 
		{
			TWCR = (1 << TWINT) | (1 << TWEN);
		}
		else
		{
			TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
		}

		while (!(TWCR & (1 << TWINT)));
		if ( (TW_STATUS == TW_MR_DATA_ACK) || (TW_STATUS == TW_MR_DATA_NACK) )
		{
			*out = TWDR;
			out++;
			length--;
		}
	}

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

	return old_length - length;
}

unsigned char WriteToEprom( unsigned char length, unsigned char *in)
{
	unsigned char old_length = length;

	while( length )
	{
		TWDR = *in;
		TWCR = (1 << TWINT) | (1 << TWEN);
		while ( !( TWCR & ( 1 << TWINT ) ) );

		if ( TW_STATUS == TW_MT_DATA_ACK )
		{
			in++;
			length--;
		}
	}

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

	return old_length - length;
}






